﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DiracTCC.Business;
using System.Windows.Forms;
using System.Data;
using System.Windows.Forms.DataVisualization.Charting;
using System.IO;

namespace DiracTCC.WinForm
{
    public class GraphHelper
    {
        public static string GetSubBlockGrid(FrameInfo frame, SubBlockArray array, int mainWidth, int mainHeight)
        {
            StringBuilder html = new StringBuilder();
            int[] lenght = frame.GetSubBlockLenghtArray();

            if (string.IsNullOrEmpty(frame.SubBlockLenght) || !frame.SubBlockLenght.Contains("x"))
                return string.Empty;

            int cellWidth = (mainWidth - 2 * lenght[0]) / lenght[0];
            int cellHeight = (mainHeight - 2 * lenght[1]) / lenght[1];

            int oneDivWidth = cellWidth - 2;
            int oneDivHeight = cellHeight - 2;

            int fourDivWidth = (mainWidth - 6 * lenght[0]) / (2 * lenght[0]);
            int fourDivHeight = (mainHeight - 6 * lenght[1]) / (2 * lenght[1]);

            int sixteenDivWidth = (mainWidth - 10 * lenght[0]) / (4 * lenght[0]);
            int sixteenDivHeight = (mainHeight - 10 * lenght[1]) / (4 * lenght[1]);

            // recalculate everthing!!!
            fourDivHeight = (sixteenDivHeight) * 2;
            fourDivWidth = (sixteenDivWidth) * 2;

            oneDivHeight = (sixteenDivHeight) * 4;
            oneDivWidth = (sixteenDivWidth) * 4;

            cellHeight = oneDivHeight + 2;
            cellWidth = oneDivWidth + 2;

            mainHeight = (cellHeight) * lenght[1] + 2;
            mainWidth = (cellWidth) * lenght[0] + 2;

            html.AppendLine(@"<html>
<head>
    <style type='text/css'>
        body
        {
            font-size: 1px;
        }
        .mainDiv
        {
            width:" + mainWidth.ToString() + @"px; height:" + mainHeight.ToString() + @"px; border: solid 1px black;
        }
        .cellDiv
        {
            width:" + cellWidth.ToString() + "px; height:" + cellHeight.ToString() + @"px; border: solid 1px black; float: left; display: block;
        }
        .oneSubBlock
        {
            width:" + oneDivWidth.ToString() + "px; height:" + oneDivHeight.ToString() + @"px; border: solid 1px black; float: left; display: block;
        }
        .fourSubBlock
        {
            width:" + fourDivWidth.ToString() + "px; height:" + fourDivHeight.ToString() + @"px; border: solid 1px black; float: left; display: block;
        }
        .sixteenSubBlock
        {
            width:" + sixteenDivWidth.ToString() + "px; height:" + sixteenDivHeight.ToString() + @"px; border: solid 1px black; float: left; display: block;
        }
        .Intra
        {
            background-color: #FFAAAA;
        }
        .Ref1Only
        {
            background-color: #B3B3FF;
        }
        .Ref2Only
        {
            background-color: #FFFFB3;
        }
        .Ref1AndRef2
        {
            background-color: #AAFFC6;
        }
    </style>
</head>
<body>
    <div class='mainDiv'>");

            for (int i = 0; i < lenght[1]; i++)
            {
                for (int j = 0; j < lenght[0]; j++)
                {
                    var subBlock = array.GetSubBlock(j, i);
                    html.AppendLine("<div class='cellDiv'>");
                    html.AppendLine(GetTableFromSubBlockSplitMode(subBlock.SplitMode, subBlock.PredictionModes));
                    html.AppendLine("</div>");
                }
            }
            html.AppendLine("</div></body></html>");

            return html.ToString();
        }

        public static string GetTableFromSubBlockSplitMode(SubBlockSplitMode mode, SubBlockPredictionMode[] pred)
        {
            StringBuilder html = new StringBuilder();
            switch (mode)
            {
                case SubBlockSplitMode.None:
                    return "<div class='oneSubBlock " + pred[0].ToString() + "'></div>";
                case SubBlockSplitMode.Sub2x2:
                    for (int i = 0; i < 4; i++)
                    {
                        html.Append("<div class='fourSubBlock " + pred[i].ToString() + "'></div>");
                    }
                    return html.ToString();
                case SubBlockSplitMode.Sub4x4:
                    for (int i = 0; i < 16; i++)
                    {
                        html.Append("<div class='sixteenSubBlock " + pred[i].ToString() + "'></div>");
                    }
                    return html.ToString();
            }

            return null;
        }

        public static void FillDataGrid(List<GraphPoint> points, DataGridView grid)
        {
            DataTable tbl = new DataTable();

            foreach (var xPos in points.Select(x => x.x).Distinct().OrderBy(x => x))
            {
                tbl.Columns.Add(xPos.ToString());
            }

            foreach (var yPos in points.Select(x => x.y).Distinct().OrderBy(x => x))
            {
                object[] info = new object[tbl.Columns.Count];
                int j = 0;

                foreach (var xPos in points.Where(x => x.y == yPos).Select(x => x.x).OrderBy(x => x))
                {
                    info[j++] = points.First(a => a.x == xPos && a.y == yPos).z;
                }

                tbl.Rows.Add(info);
            }

            grid.DataSource = tbl;
        }

        public static void Fill3DChart(List<GraphPoint> points, Chart chart)
        {
            foreach (var yPos in points.Select(x => x.y).Distinct().OrderBy(x => x))
            {
                if (chart.Series.Count(x => x.Name == "xPos" + yPos.ToString()) == 0)
                {
                    chart.Series.Add("xPos" + yPos.ToString());
                    chart.Series["xPos" + yPos.ToString()].ChartType = SeriesChartType.Column;
                }

                foreach (var xPos in points.Select(x => x.x).Distinct().OrderBy(x => x))
                {
                    var zPosition = points.First(x => x.y == yPos && x.x == xPos);
                    chart.Series["xPos" + yPos.ToString()].Points.Add(new DataPoint { YValues = new double[1] { zPosition.z } });
                }
            }
        }

        public static void Clear3DChart(Chart chart)
        {
            for (int i = 0; i < chart.Series.Count; i++)
            {
                chart.Series[i].Points.Clear();
            }
        }

        public static void GenerateSadBetweenVideos(Chart chart, DataGridView grid, string pathBmpFolder1, string pathBmpFolder2)
        {
            var folderPath1 = pathBmpFolder1.Substring(0, pathBmpFolder1.LastIndexOf('\\'));
            var folderPath2 = pathBmpFolder2.Substring(0, pathBmpFolder2.LastIndexOf('\\'));

            var images1 = Directory.GetFiles(folderPath1);
            var images2 = Directory.GetFiles(folderPath2);

            var xmlPath = Path.Combine(
                folderPath1.Substring(0, folderPath1.LastIndexOf('\\')),
                "sadComparisonData.dat");

            DataTable tbl = new DataTable("SadDataComparision");
            if (File.Exists(xmlPath))
            {
                tbl.ReadXml(xmlPath);
            }
            else
            {
                tbl.Columns.Add("frame");
                tbl.Columns.Add("sad");

                for (int i = 0; i < images1.Count(); i++)
                {
                    var comparer = new BmpComparer(images1[i], images2[i]);
                    tbl.Rows.Add((i + 1), comparer.Difference);
                }

                tbl.WriteXml(xmlPath, XmlWriteMode.WriteSchema);
            }
            

            if (chart.Series.Count(a => a.Name == "sad") == 0)
            {
                chart.Series.Add("sad");
                chart.Series["sad"].ChartType = SeriesChartType.Line;
            }
            chart.Series["sad"].Points.Clear();

            for (int i = 0; i < tbl.Rows.Count; i++)
            {
                chart.Series["sad"].Points.Add(new DataPoint { XValue = double.Parse(tbl.Rows[i]["frame"].ToString()), YValues = new double[1] { double.Parse(tbl.Rows[i]["sad"].ToString()) } });
            }

            grid.DataSource = tbl;
        }
    }
}
